package org.jeecg.modules.bj.util;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.rmi.RemoteException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class WordUtils {

    public static void readwriteWord(InputStream in, OutputStream os,Map<String,Object> params) throws IOException,InvalidFormatException{
        XWPFDocument document = new XWPFDocument(OPCPackage.open(in));
        replaceParams(document, params);
        document.write(os);
        close(in);
        close(os);
    }

    public static void readwriteWord(InputStream in, OutputStream os, Map<String, Object> params, int[] tableIndex, List<List<String[]>> tables) throws IOException, InvalidFormatException {
        XWPFDocument document = new XWPFDocument(OPCPackage.open(in));
        replaceParams(document, params);
        if (tableIndex.length != tables.size()) throw new RemoteException("表格下表数量与表格参数数量不一致");
        for (int i = 0; i < tableIndex.length; i++) {
            changeTable(document, params, i, tables.get(i));
        }
        document.write(os);
    }

    private static void replaceParams(XWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFParagraph> iterator = doc.getParagraphsIterator();
        XWPFParagraph paragraph;
        while (iterator.hasNext()) {
            paragraph = iterator.next();
            replaceParam(paragraph, params);
        }
    }

    public static void changeTable(XWPFDocument doc, Map<String, Object> params, int tableIndex, List<String[]> tableList) {
        List<XWPFTable> tables = doc.getTables();
        XWPFTable table = tables.get(tableIndex);
        replaceTableParams(doc, params);
        insertTable(table, tableList);
    }

    private static void replaceTableParams(XWPFDocument doc, Map<String, Object> params) {
        Iterator<XWPFTable> iterator = doc.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        List<XWPFParagraph> paras;
        while (iterator.hasNext()) {
            table = iterator.next();
            if (matcher(table.getText()).find()) {
                rows = table.getRows();
                for (XWPFTableRow row : rows) {
                    cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        paras = cell.getParagraphs();
                        for (XWPFParagraph para : paras) {
                            replaceParam(para, params);
                        }
                    }
                }
            }
        }
    }

    private static void insertTable(XWPFTable table, List<String[]> tableList) {
        for (int i = 0; i < tableList.size(); i++) {
            table.createRow();
        }
        int length = table.getRows().size();
        for (int i = 1; i < length; i++) {
            XWPFTableRow newRow = table.getRow(i);
            List<XWPFTableCell> cells = newRow.getTableCells();
            for (int j = 0; j < cells.size(); j++) {
                XWPFTableCell cell = cells.get(j);
                cell.setText(tableList.get(i - 1)[j]);
            }
        }
    }

    private static void replaceParam(XWPFParagraph paragraph, Map<String, Object> params) {
        List<XWPFRun> runs;
        Matcher matcher;
        String runText = "";
        if (matcher(paragraph.getParagraphText()).find()) {
            runs = paragraph.getRuns();
            int j = runs.size();
            for (int i = 0; i < j; i++) {
                runText += runs.get(0).toString();
                if (!((j - 1) == i)) {
                    paragraph.removeRun(0);

                }
            }
            matcher = matcher(runText);
            if (matcher.find()) {
                while ((matcher = matcher(runText)).find()) {
                    runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1))));
                }
                runs.get(0).setText(runText, 0);

            }
        }
    }

    private static Matcher matcher(String str) {
        Pattern pattern = Pattern.compile("\\$\\{(.+?)\\}", Pattern.CASE_INSENSITIVE);
        Matcher matcher = pattern.matcher(str);
        return matcher;
    }

    private static void close(InputStream is){
        if(is!=null){
            try{
                is.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

    private static void close(OutputStream os){
        if(os!=null){
            try{
                os.close();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }

}
